package com.example;

import org.junit.jupiter.api.Test;

import java.util.Random;
import java.util.concurrent.*;

public class Demo03Test {

    /**
     * 1. 使用 thenCompose() 组合两个独立的future
     * 假设你想从一个远程 API 中获取一个用户的详细信息，一旦用户信息可用，你想从另外一个服务中获取他的贷方。
     * 考虑下以下两个方法 getUserDetail() 和 getCreditRating() 的实现
     */
    @Test
    public void test01() throws ExecutionException, InterruptedException {
        /*
        当使用了 thenApply() 后是最终结果是一个嵌套的CompletableFuture
         */
        //
//        CompletableFuture<CompletableFuture<Double>> completableFuture =
//                getUserDetail(1).thenApply(this::getCreditRating);
//        Double result = completableFuture.get().get();

        /*
        如果你想获取最终的结果给最顶层 future，使用 thenCompose()方法代替
        因此，规则就是如果你的回调函数返回一个 CompletableFuture，
        但是你想从 CompletableFuture 链中获取一个直接合并后的结果，这时候你可以使用 thenCompose()。
         */
        CompletableFuture<Double> completableFuture =
                getUserDetail(1).thenCompose(this::getCreditRating);
        System.out.println("result = " + completableFuture.get());
    }
    CompletableFuture<String> getUserDetail(Integer userId){
        return CompletableFuture.supplyAsync(() -> "userDetail " + userId);
    }
    CompletableFuture<Double> getCreditRating(String user){
        return CompletableFuture.supplyAsync(() -> (double) user.length());
    }

    /**
     * 2. 使用 thenCombine() 结合两个独立的 future
     * 虽然 thenCompose() 被用于当一个 future 依赖另外一个 future 的时候用来组合两个 future。
     * thenCombine()被用来当两个独立的 Future 都完成的时候，用来做一些事情。
     */
    @Test
    public void test02() throws ExecutionException, InterruptedException {
        System.out.println("log: a");
        CompletableFuture<Integer> aFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 2;
        });
        System.out.println("log: b");
        CompletableFuture<Integer> bFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 5;
        });
        System.out.println("log: a*b");
        CompletableFuture<Integer> combinedFuture = aFuture.thenCombine(bFuture, (a, b) -> a * b);
        System.out.println("result: " + combinedFuture.get());
    }
}
